package utils

import (
	"context"
	"fmt"
	"runtime/debug"
	"sync"
)

type ParallelRunCallback func(ctx context.Context) error

func ParallelRun(ctx context.Context, callbacks ...ParallelRunCallback) error {
	if len(callbacks) == 0 {
		return nil
	}
	if len(callbacks) == 1 {
		return callbacks[0](ctx)
	}

	var wg sync.WaitGroup
	wg.Add(len(callbacks))
	errChan := make(chan error, len(callbacks))
	for _, callback := range callbacks {
		go func(doWork func(context.Context) error) {
			defer wg.Done()
			defer func() {
				if r := recover(); r != nil {
					var err error
					if e, ok := r.(error); ok {
						err = fmt.Errorf("panic:%v", e)
					} else {
						err = fmt.Errorf("panic:%v", r)
					}
					fmt.Println(err.Error(), string(debug.Stack()))
					errChan <- err
				}
			}()
			if err := doWork(ctx); err != nil {
				errChan <- err
			}
		}(callback)
	}

	wg.Wait()
	close(errChan)

	errs := make([]error, 0, len(errChan))
	for err := range errChan {
		errs = append(errs, err)
	}
	if len(errs) > 0 {
		return fmt.Errorf("ParallelRun errors:%v", errs)
	}
	return nil
}
